using NetTopologySuite.Geometries;
using Newtonsoft.Json.Linq;

namespace KrigingTest;

public class PointHelper
{
    /// <summary>
    /// 多边形的任意一个顶点是否在另一个多边形区域内
    /// </summary>
    /// <param name="longitude">经度</param>
    /// <param name="latitude">纬度</param>
    /// <param name="polygonArea">目标多边形区域</param>
    /// <returns></returns>
    public static bool IsAnyVertexInPolygon(double longitude, double latitude, List<Tuple<double, double>> polygonArea)
    {
        var maxLon = longitude;
        var maxLat = latitude;
        var minLon = longitude - 0.01;
        var minLat = latitude - 0.01;

        var polygonToCheck = new List<Tuple<double, double>>
        {
            new(maxLon, maxLat),
            new(maxLon, minLat),
            new(minLon, maxLat),
            new(minLon, minLat)
        };

        foreach (var vertex in polygonToCheck)
        {
            if (IsPointInPolygon(vertex.Item1, vertex.Item2, polygonArea))
            {
                return true;
            }
        }

        return false;
    }

    public static bool IsPointInPolygon(double lon, double lat, Polygon polygon)
    {
        // 3. 创建NetTopologySuite中的多边形对象
        var geometryFactory = new GeometryFactory();

        // 4. 创建点
        var point = geometryFactory.CreatePoint(new Coordinate(lon, lat));

        // 5. 检查点是否在多边形内
        return polygon.Contains(point);
    }

    public static Polygon BuildPolygon(string geoJsonFilePath, bool convertTo3857 = false)
    {
        // 1. 加载GeoJSON文件
        var geoJson = LoadGeoJson(geoJsonFilePath);

        // 2. 解析出多边形坐标 (假设GeoJSON文件中存的是Polygon)
        var coordinates = geoJson["features"][0]["geometry"]["coordinates"][0]; // 可能需要根据具体文件格式调整路径
        var polygonCoordinates = new List<Coordinate>();

        foreach (var coord in coordinates)
        {
            double x = coord[0].Value<double>();
            double y = coord[1].Value<double>();
            if (convertTo3857)
            {
                var epsg = ConvertToEPSG3857(x, y);
                polygonCoordinates.Add(new Coordinate(epsg.x, epsg.y));
            }
            else
            {
                polygonCoordinates.Add(new Coordinate(x, y));
            }
        }

        // 3. 创建NetTopologySuite中的多边形对象
        var geometryFactory = new GeometryFactory();
        var polygon = geometryFactory.CreatePolygon(polygonCoordinates.ToArray());

        return polygon;
    }

    public static JObject LoadGeoJson(string path)
    {
        var geoJsonContent = File.ReadAllText(path);
        return JObject.Parse(geoJsonContent);
    }

    /// <summary>
    /// 点是否在多边形区域内
    /// </summary>
    /// <param name="longitude">经度</param>
    /// <param name="latitude">纬度</param>
    /// <param name="polygon">坐标范围</param>
    /// <returns></returns>
    public static bool IsPointInPolygon(double longitude, double latitude, List<Tuple<double, double>> polygon)
    {
        var j = polygon.Count - 1;
        var inside = false;

        for (var i = 0; i < polygon.Count; i++)
        {
            if ((polygon[i].Item2 > latitude) != (polygon[j].Item2 > latitude) &&
                (longitude <
                 (polygon[j].Item1 - polygon[i].Item1) * (latitude - polygon[i].Item2) /
                 (polygon[j].Item2 - polygon[i].Item2) + polygon[i].Item1))
            {
                inside = !inside;
            }

            j = i;
        }

        return inside;
    }

    public static Polygon CreatePolygonFromList(List<Tuple<double, double>> polygonArea, bool convertTo3857 = false)
    {
        var coordinates = polygonArea.Select(p =>
        {
            var coord = convertTo3857 ? ConvertToEPSG3857(p.Item1, p.Item2) : (p.Item1, p.Item2);
            return new Coordinate(coord.Item1, coord.Item2);
        }).ToArray();

        var geometryFactory = new GeometryFactory();
        return geometryFactory.CreatePolygon(coordinates);
    }
    
    public static bool[,] CreateMaskGrid(double minLon, double maxLon, double minLat, double maxLat, int rows, int cols, Polygon polygon)
    {
        bool[,] mask = new bool[rows, cols];
        double dLon = (maxLon - minLon) / cols;
        double dLat = (maxLat - minLat) / rows;
    
        for (int i = 0; i < rows; i++)
        {
            for (int j = 0; j < cols; j++)
            {
                double lon = minLon + j * dLon;
                double lat = minLat + i * dLat;
                mask[i, j] = polygon.Contains(new Point(new Coordinate(lon, lat)));
            }
        }
        return mask;
    }

    public static (double x, double y) ConvertToEPSG3857(double lon, double lat)
    {
        const double R = 6378137; // 地球半径
        double x = R * lon * Math.PI / 180;
        double y = R * Math.Log(Math.Tan(Math.PI / 4 + lat * Math.PI / 180 / 2));
        return (x, y);
    }
}